
#region Imported Namespaces
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Reflection;
using System.Resources;
using System.Web.UI;
using System.Web.UI.Design;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
#endregion

namespace PHSRAG.WebControls
{
	#region Class SwitchingPanel
	/// <summary>
	/// The SwitchingPanel is a control that supports two templates: one for a collapsed view and another for an
	/// expanded view. What you put in those templates is really up to you.
	/// The expand/collapse can either be done client-side or server-side. The former is the default.
	/// The ExpadningPanel relies on the fact that the CommandName assigned to the control which instigates the
	/// expansion (set via the AlternateViewEnabler property) is "Alternate", and the CommandName assigned to the control which
	/// instigates the collapse (set via the NormalViewEnabler property) is "Normal". 
	/// </summary>
	/// <remarks>
	/// Pages which wish to display one of two set of controls at any point in time should use this control.
	/// </remarks>
	/// <example>
	/// <p>The following example shows how the page would use this control. The registration of the control can be done
	/// simply by dropping the control on the page in design mode.</p>
	/// <p>Notice the setting of the <b>AlternateViewEnabler</b> and <b>NormalViewEnabler</b> properties to the IDs of
	/// the ImageButtons.</p>
	/// <code>
	/// <![CDATA[
	/// <%@ Register TagPrefix="cc1" Namespace="PHSRAG.WebControls" Assembly="PHSRAG.WebControls" %>
	/// ...
	/// <body>
	/// ...
	/// <cc1:SwitchingPanel id="switchingPanel" runat="server" AlternateViewEnabler="viewAlternate" NormalViewEnabler="viewNormal" IsAlternateView="False">
	///		<NormalTemplate>
	///			<table>
	///				<tr>
	///					<td><asp:ImageButton runat="server" ImageUrl="Images/RightArrow.gif" CommandName="Alternate" id="viewAlternate" Width="19px" Height="22px" /></td>
	///					<td>You are viewing the contents of the normal panel</td>
	///				</tr>
	///			</table>
	///		</NormalTemplate>
	///		<AlternateTemplate>
	///			<table>
	///				<tr>
	///					<td><asp:ImageButton runat="server" ImageUrl="Images/BottomArrow.gif" CommandName="Normal" id="viewNormal" Width="19px" Height="22px"/></td>
	///					<td>You are viewing the contents of the alternate panel</td>
	///				</tr>
	///			</table>
	///		</AlternateTemplate>
	/// </cc1:SwitchingPanel>
	/// ...
	/// </body>
	/// ]]>
	/// </code>
	/// </example>
	[ToolboxData("<{0}:SwitchingPanel runat=server />"), Designer(typeof(SwitchingPanelDesigner))]
	public class SwitchingPanel : System.Web.UI.WebControls.WebControl, INamingContainer
	{
		#region Constants
		private const string AlternateCommandName = "Alternate";
		private const string AlternatePanelID = "alternateContainer";
		private const string AlternateViewEnablerKey = "alternateViewEnabler_B8880691-40F9-49df-9C4B-B24C5250C0B2";
		private const string ClientScriptKey = "clientScript_B8880691-40F9-49df-9C4B-B24C5250C0B2";
		private const string NormalCommandName = "Normal";
		private const string NormalViewEnablerKey = "normalViewEnabler_B8880691-40F9-49df-9C4B-B24C5250C0B2";
		private const string NormalPanelID = "normalContainer";
		private const string EnableClientScriptKey = "enableClientScript_B8880691-40F9-49df-9C4B-B24C5250C0B2";
		private const string StartupScriptKey = "startupScript_B8880691-40F9-49df-9C4B-B24C5250C0B2";
		private const string StateKey = "state_B8880691-40F9-49df-9C4B-B24C5250C0B2";
		#endregion

		#region Instance Variables
		private Panel			alternatePanel;
		private ITemplate		alternateTemplate;
		private Panel			normalPanel;
		private ITemplate		normalTemplate;
		private bool			preRendered;
		#endregion

		#region Public Properties
		/// <summary>
		/// Get/Set the template which defines the normal view.
		/// </summary>
		[Description("Get/Set the template which defines the normal view"),
		PersistenceMode(PersistenceMode.InnerProperty), TemplateContainer(typeof(SwitchingPanel))]
		public ITemplate NormalTemplate 
		{
			get { return normalTemplate; }
			set { normalTemplate = value; }
		}

		/// <summary>
		/// Get/Set the control which instigates the switch to the normal view.
		/// </summary>
		[Description("Get/Set the control which instigates the switch to the normal view"),
		Bindable(true), Category("Behavior")]
		public virtual string NormalViewEnabler 
		{
			get 
			{
				string s = ViewState[NormalViewEnablerKey] as string;
				return (s != null) ? s : "";
			}
			set 
			{
				ViewState[NormalViewEnablerKey] = value;
			}
		}

		/// <summary>
		/// Get/Set whether the switching occurs client-side.
		/// </summary>
		[Description("Get/Set whether the switching occurs client-side"),
		Bindable(true), DefaultValue(true), Category("Behavior")]
		public virtual bool EnableClientScript 
		{
			get 
			{
				object o = ViewState[EnableClientScriptKey];
				return (o != null) ? (bool)o : true;
			}
			set 
			{
				ViewState[EnableClientScriptKey] = value;
			}
		}

		/// <summary>
		/// Get/Set the template which defines the alternate view.
		/// </summary>
		[Description("Get/Set the template which defines the alternate view"),
		PersistenceMode(PersistenceMode.InnerProperty), TemplateContainer(typeof(SwitchingPanel))]
		public ITemplate AlternateTemplate 
		{
			get	{ return alternateTemplate; }
			set	{ alternateTemplate = value; }
		}

		/// <summary>
		/// Get/Set the control which instigates the switch to the alternate view.
		/// </summary>
		[Description("Get/Set the control which instigates the switch to the alternate view"),
		Bindable(true), Category("Behavior")]
		public string AlternateViewEnabler 
		{
			get 
			{
				string s = ViewState[AlternateViewEnablerKey] as string;
				return (s != null) ? s : "";
			}
			set 
			{
				ViewState[AlternateViewEnablerKey] = value;
			}
		}

		/// <summary>
		/// Get/Set the alternate view.
		/// </summary>
		[Description("Get/Set the alternate view"),
		Bindable(true), DefaultValue(false), Category("Appearance")]
		public bool IsAlternateView 
		{
			get 
			{
				object o = ViewState[StateKey];
				return (o != null) ? (bool)o : false;
			}
			set 
			{
				ViewState[StateKey] = value;
			}
		}
		#endregion

		#region Overrides
		/// <summary>
		/// Ensure that all child controls are created and return their collection.
		/// </summary>
		public override ControlCollection Controls
		{
			get { EnsureChildControls(); return base.Controls; }
		}

		/// <summary>
		/// Create all child controls of SwitchingPanel. The normal/alternate templates map to two panels within each
		/// of which the contents of the template are created. Switching from one to another is then as simple as
		/// toggling the visibility of each of those two panels (either client-side or server-side).
		/// </summary>
		protected override void CreateChildControls()
		{
			if (alternateTemplate == null)
				throw new Exception("You MUST declare the AlternateTemplate element");
			if (normalTemplate == null)
				throw new Exception("You MUST declare the NormalTemplate element");

			Controls.Clear();

			alternatePanel = new Panel();
			alternatePanel.ID = AlternatePanelID;
			alternateTemplate.InstantiateIn(alternatePanel);
			Controls.Add(alternatePanel);

			normalPanel = new Panel();
			normalPanel.ID = NormalPanelID;
			normalTemplate.InstantiateIn(normalPanel);
			Controls.Add(normalPanel);

			// The ExpadningPanel relies on the fact that the CommandName assigned to the control which instigates the
			// expansion is "Alternate", and the CommandName assigned to the control which instigates the collapse is
			// "Normal".

			Control c = FindControl(AlternateViewEnabler);
			if (c.GetType().GetProperty("CommandName").GetValue(c, null).ToString() != AlternateCommandName)
				throw new Exception(string.Format("The AlternateViewEnabler control MUST have its CommandName property set to {0}", AlternateCommandName));

			c = FindControl(NormalViewEnabler);
			if (c.GetType().GetProperty("CommandName").GetValue(c, null).ToString() != NormalCommandName)
				throw new Exception(string.Format("The NormalViewEnabler control MUST have its CommandName property set to {0}", NormalCommandName));
		}

		/// <summary>
		/// Set the normal/alternate state depending on which control raised the event.
		/// </summary>
		/// <param name="source">The control which raised an event</param>
		/// <param name="args">Event arguments associated with the event</param>
		/// <returns></returns>
		protected override bool OnBubbleEvent(object source, EventArgs args)
		{
			CommandEventArgs commandEventArgs = args as CommandEventArgs;
			if (commandEventArgs != null) 
			{
				IsAlternateView = (string.Compare(commandEventArgs.CommandName, "Alternate", true) == 0);
				return true;
			}
			return false;
		}

		/// <summary>
		/// Initialize the normal/alternate panels.
		/// If client-side behavior (the default) is enabled, register the scripts that handle the toggling between
		/// normal/alternate states.
		/// </summary>
		/// <param name="e">Event arguments associated with the event</param>
		protected override void OnPreRender(EventArgs e)
		{
			InitializePanels();

			if (EnableClientScript)
				RegisterClientScripts();

			preRendered = true;
			base.OnPreRender(e);
		}

		/// <summary>
		/// If the control has not been pre-rendered yet, do the rendering. The logic is very similar to that of the
		/// pre-render method.
		/// </summary>
		/// <param name="writer">The writer into which to render</param>
		protected override void Render(HtmlTextWriter writer)
		{
			if (!preRendered)
			{
				EnsureChildControls();
				InitializePanels();
			}

			base.Render(writer);
		}
		#endregion
		/// <summary>
		/// Ensure that the styles set on the SwitchingPanel propagates to both the normal/alternate panels.
		/// Set the visibility of those panels based on the current state.
		/// </summary>
		#region Private Methods
		private void InitializePanels()
		{
			alternatePanel.MergeStyle(ControlStyle);
			normalPanel.MergeStyle(ControlStyle);

			bool isAlternateViewVisible = IsAlternateView;
			SetPanelVisibility(alternatePanel, isAlternateViewVisible);
			SetPanelVisibility(normalPanel, !isAlternateViewVisible);
		}

		/// <summary>
		/// Register the client scripts which will be used to toggle the normal/alternate state. There are two
		/// separate scripts: one to actually do the state toggling, and another to call on the first script during
		/// page load. The first script is static and is stored in the assmebly resource. The second script is created
		/// on-the-fly (since we need the client IDs of controls).
		/// </summary>
		private void RegisterClientScripts()
		{
            if (!Page.ClientScript.IsClientScriptBlockRegistered(ClientScriptKey))
			{
                Page.ClientScript.RegisterClientScriptBlock(GetType( ), ClientScriptKey, (new ResourceManager(GetType())).GetResourceSet(
					System.Globalization.CultureInfo.CurrentCulture, true, true).GetString("ClientScript"));
			}

            if (!Page.ClientScript.IsStartupScriptRegistered(StartupScriptKey))
			{
				string script = string.Format( 
					"<script language='javascript'>\r\n" +
					"LoadSwitchingPanel('{0}','{1}','{2}','{3}');\r\n" +
					"</script>\r\n",
					FindControl(AlternateViewEnabler).ClientID, FindControl(NormalViewEnabler).ClientID,
					alternatePanel.ClientID, normalPanel.ClientID);

                Page.ClientScript.RegisterStartupScript(GetType( ), StartupScriptKey, script);
			}
		}

		/// <summary>
		/// Set the visibility of the normal/alternate panels depending on the current state.
		/// </summary>
		/// <param name="panel">The panel whose visibility is to be set</param>
		/// <param name="visible">True to show the panel, false to hide</param>
		private void SetPanelVisibility(Panel panel, bool visible) 
		{
			if (EnableClientScript)
				panel.Style["display"] = visible ? "block" : "none";
			else 
				panel.Visible = visible;
		}
		#endregion
	}
	#endregion

	#region Class SwitchingPanelDesigner
	/// <summary>
	/// The SwitchingPanelDesigner helps in design-time activities of the SwitchingPanel control.
	/// </summary>
	/// <remarks>
	/// This class cannot be used directly.
	/// </remarks>
	public class SwitchingPanelDesigner : TemplatedControlDesigner
	{
		#region Instance Variables
		private TemplateEditingVerb[]	templateEditingVerbs;
		#endregion

		#region Overrides
		/// <summary>
		/// Creates a template editing frame for the specified verb.
		/// </summary>
		/// <param name="verb">The template editing verb to create a template editing frame for</param>
		/// <returns></returns>
        [System.Obsolete]
        protected override ITemplateEditingFrame CreateTemplateEditingFrame(TemplateEditingVerb verb)
		{
			ITemplateEditingFrame frame = null;
			if (templateEditingVerbs != null)  
			{
				ITemplateEditingService editingService = (ITemplateEditingService)GetService(typeof(ITemplateEditingService));
				if (editingService != null) 
				{
					Style style = ((SwitchingPanel)Component).ControlStyle;
					string templateName = verb.Text.Replace(" ", "");
					frame = editingService.CreateFrame(this, verb.Text, new string[]{templateName}, style, null);
				}
			}

			return frame;
		}

		/// <summary>
		/// Gets the cached template editing verbs
		/// </summary>
		/// <returns>An array of TemplateEditingVerb objects</returns>
        [System.Obsolete]
        protected override TemplateEditingVerb[] GetCachedTemplateEditingVerbs()
		{
			if (templateEditingVerbs == null) 
			{
				templateEditingVerbs = new TemplateEditingVerb[2];
				templateEditingVerbs[0] = new TemplateEditingVerb("Normal Template", 0, this); 
				templateEditingVerbs[1] = new TemplateEditingVerb("Alternate Template", 1, this); 
			}

			return templateEditingVerbs;
		}

		/// <summary>
		/// Gets the HTML that is used to represent the control at design time.
		/// </summary>
		/// <returns>The HTML that is used to represent the control at design time</returns>
		public override string GetDesignTimeHtml()
		{
			SwitchingPanel panel = (SwitchingPanel)Component;
			if ((panel.AlternateTemplate == null) && (panel.NormalTemplate == null))
				return CreatePlaceHolderDesignTimeHtml("Right-click to edit the normal/alternate templates");

			panel.DataBind();
			return base.GetDesignTimeHtml();
		}

		/// <summary>
		/// Gets the template's content
		/// </summary>
		/// <param name="editingFrame">The template editing frame to retrieve the content of</param>
		/// <param name="templateName">The name of the template</param>
		/// <param name="allowEditing">true if the template's content can be edited; false otherwise</param>
		/// <returns>The content of the template</returns>
        [System.Obsolete]
        public override string GetTemplateContent(ITemplateEditingFrame editingFrame, string templateName, out bool allowEditing)
		{
			allowEditing = true;
			SwitchingPanel panel = (SwitchingPanel)Component;

			if (templateEditingVerbs != null)  
				GetTextFromTemplate((templateName == "NormalTemplate") ? panel.NormalTemplate : panel.AlternateTemplate);
			return string.Empty;
		}

		/// <summary>
		/// Sets the specified template's content to the specified content
		/// </summary>
		/// <param name="editingFrame">The template editing frame to provide content for</param>
		/// <param name="templateName">The name of the template</param>
		/// <param name="templateContent">The content to set for the template</param>
        [System.Obsolete]
        public override void SetTemplateContent(ITemplateEditingFrame editingFrame, string templateName, string templateContent)
		{
			if (templateEditingVerbs != null) 
			{
				SwitchingPanel panel = (SwitchingPanel)Component;
				ITemplate template = null;

				if ((templateContent != null) && (templateContent.Length != 0)) 
					template = GetTemplateFromText(templateContent);

				if (templateName == "NormalTemplate") 
					panel.NormalTemplate = template;
				else
					panel.AlternateTemplate = template;
			}
		}

		#endregion
	}
	#endregion
}

// --- EOF ---
